/*********************************************************
 *********************************************************
 ********************                  *******************
 *************                                ************
 *******                  _oo0oo_                  *******
 ***                     o8888888o                     ***
 *                       88" . "88                       *
 *                       (| -_- |)                       *
 *                       0\  =  /0                       *
 *                     ___/`---'\___                     *
 *                   .' \\|     |// '.                   *
 *                  / \\|||  :  |||// \                  *
 *                 / _||||| -:- |||||- \                 *
 *                |   | \\\  -  /// |   |                *
 *                | \_|  ''\---/''  |_/ |                *
 *                \  .-\__  '-'  ___/-. /                *
 *              ___'. .'  /--.--\  `. .'___              *
 *           ."" '<  `.___\_<|>_/___.' >' "".            *
 *          | | :  `- \`.;`\ _ /`;.`/ - ` : | |          *
 *          \  \ `_.   \_ __\ /__ _/   .-` /  /          *
 *      =====`-.____`.___ \_____/___.-`___.-'=====       *
 *                        `=---='                        *
 *      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~      *
 *********__佛祖保佑__永无BUG__验收通过__钞票多多__*********
 *********************************************************/
package org.jbase.ext.beetl;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;

/**
 * Project: fw_common <br/>
 * File: ShiroFunctionPackage.java <br/>
 * Class: com.yxt.common.ext.beetl.ShiroFunctionPackage <br/>
 * Description: <描述类的功能>. <br/>
 * Copyright: Copyright (c) 2011 <br/>
 * Company: http://www.yxtsoft.com/ <br/>
 * Makedate: 2016年1月15日 下午3:34:16 <br/>
 * 
 * @author liuzhanhong
 * @version 1.0
 * @since 1.0
 */
@Service("shiro")
public class ShiroFunctionPackage implements JbaseFunctionPackage {
	/**
	 * The guest tag
	 * 
	 * @return
	 */
	public boolean isGuest() {
		return getSubject() == null || getSubject().getPrincipal() == null;
	}

	/**
	 * The user tag
	 * 
	 * @return
	 */
	public boolean isUser() {
		return getSubject() != null && getSubject().getPrincipal() != null;
	}

	/**
	 * The authenticated tag
	 * 
	 * @return
	 */
	public boolean isAuthenticated() {
		return getSubject() != null && getSubject().isAuthenticated();
	}

	public boolean isNotAuthenticated() {
		return !isAuthenticated();
	}

	/**
	 * The principal tag
	 * 
	 * @param map
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public String principal(Map map) {
		String strValue = null;
		if (getSubject() != null) {

			// Get the principal to print out
			Object principal;
			String type = map != null ? (String) map.get("type") : null;
			if (type == null) {
				principal = getSubject().getPrincipal();
			} else {
				principal = getPrincipalFromClassName(type);
			}
			String property = map != null ? (String) map.get("property") : null;
			// Get the string value of the principal
			if (principal != null) {
				if (property == null) {
					strValue = principal.toString();
				} else {
					strValue = getPrincipalProperty(principal, property);
				}
			}

		}

		if (strValue != null) {
			return strValue;
		} else {
			return null;
		}
	}

	/**
	 * The hasRole tag
	 * 
	 * @param roleName
	 * @return
	 */
	public boolean hasRole(String roleName) {
		return getSubject() != null && getSubject().hasRole(roleName);
	}

	/**
	 * The lacksRole tag
	 * 
	 * @param roleName
	 * @return
	 */
	public boolean lacksRole(String roleName) {
		boolean hasRole = getSubject() != null && getSubject().hasRole(roleName);
		return !hasRole;
	}

	/**
	 * The hasAnyRole tag
	 * 
	 * @param roleNames
	 * @return
	 */
	public boolean hasAnyRole(String roleNames) {
		boolean hasAnyRole = false;

		Subject subject = getSubject();

		if (subject != null) {

			// Iterate through roles and check to see if the user has one of the
			// roles
			for (String role : roleNames.split(",")) {

				if (subject.hasRole(role.trim())) {
					hasAnyRole = true;
					break;
				}

			}

		}

		return hasAnyRole;
	}

	/**
	 * The hasPermission tag
	 * 
	 * @param p
	 * @return
	 */
	public boolean hasPermission(String p) {
		return getSubject() != null && getSubject().isPermitted(p);
	}

	/**
	 * The lacksPermission tag
	 * 
	 * @param p
	 * @return
	 */
	public boolean lacksPermission(String p) {
		return !hasPermission(p);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Object getPrincipalFromClassName(String type) {
		Object principal = null;

		try {
			Class cls = Class.forName(type);
			principal = getSubject().getPrincipals().oneByType(cls);
		} catch (ClassNotFoundException e) {

		}
		return principal;
	}

	private String getPrincipalProperty(Object principal, String property) {
		String strValue = null;

		try {
			BeanInfo bi = Introspector.getBeanInfo(principal.getClass());

			// Loop through the properties to get the string value of the
			// specified property
			boolean foundProperty = false;
			for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
				if (pd.getName().equals(property)) {
					Object value = pd.getReadMethod().invoke(principal, (Object[]) null);
					strValue = String.valueOf(value);
					foundProperty = true;
					break;
				}
			}

			if (!foundProperty) {
				final String message = "Property [" + property + "] not found in principal of type ["
						+ principal.getClass().getName() + "]";

				throw new RuntimeException(message);
			}

		} catch (Exception e) {
			final String message = "Error reading property [" + property + "] from principal of type ["
					+ principal.getClass().getName() + "]";

			throw new RuntimeException(message, e);
		}

		return strValue;
	}

	private Subject getSubject() {
		return SecurityUtils.getSubject();
	}
}
